/*
 * Copyright 2011 Guidebee Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 */

//--------------------------------- PACKAGE ------------------------------------
package com.mapdigit.practices.compositeui;

//--------------------------------- IMPORTS ------------------------------------
import android.content.Context;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Stage;
import com.mapdigit.practices.compositeui.eventbroker.EventBroker;
import com.mapdigit.practices.compositeui.eventbroker.EventInspector;
import com.mapdigit.practices.compositeui.winforms.builderstrategies.CabModule;
import com.mapdigit.practices.compositeui.winforms.builderstrategies.UIContextScope;
import com.mapdigit.practices.compositeui.winforms.builderstrategies.UIElementListener;
import java.util.ArrayList;
import roboguice.application.RoboApplication;
import roboguice.config.AbstractAndroidModule;
import roboguice.config.EventManagerModule;
import roboguice.config.RoboModule;
import roboguice.event.EventManager;
import roboguice.inject.ExtrasListener;
import roboguice.inject.PreferenceListener;
import roboguice.inject.ResourceListener;
import roboguice.inject.StaticTypeListener;
import roboguice.inject.ViewListener;

//[------------------------------ MAIN CLASS ----------------------------------]
////////////////////////////////////////////////////////////////////////////////
//--------------------------------- REVISIONS ----------------------------------
// Date       Name                 Tracking #         Description
// --------   -------------------  -------------      --------------------------
// 13AUG2011  James Shen                 	      Code review
////////////////////////////////////////////////////////////////////////////////
/**
 * Defines the CabApplication{TWorkItem} as an application having a well known 
 * lifecycle and a root WorkIteminstance providing the scope for the application.
 * <P>
 * <hr>
 * <hr><b>&copy; Copyright 2011 Guidebee Pty Ltd. All Rights Reserved.</b>
 * @version     1.00, 13/08/11
 * @author      Guidebee Pty Ltd.
 */
public abstract class CabApplication<TWorkItem extends WorkItem>
        extends RoboApplication {
 
    
    @Override
    protected void initInstanceMembers() {
        contextScope = new UIContextScope(this);
        throwingContextProvider = new Provider<Context>() {
            public Context get() {
                return CabApplication.this;
            }
        };
        
        contextProvider = contextScope.scope(Key.get(Context.class), throwingContextProvider);
        resourceListener = new ResourceListener(this);
        viewListener = new ViewListener(contextProvider, this, contextScope);
        uiElementListener=new UIElementListener(contextProvider, this, (UIContextScope)contextScope);
        extrasListener = new ExtrasListener(contextProvider);
        eventManager = allowContextObservers() ? new EventBroker() : new EventManager.NullEventManager();

        if (allowPreferenceInjection())
          preferenceListener = new PreferenceListener(contextProvider, this, contextScope);


        staticTypeListeners = new ArrayList<StaticTypeListener>();
        staticTypeListeners.add(resourceListener);
    }
    
    
    @Override
    protected Injector createInjector() {
        final ArrayList<Module> modules = new ArrayList<Module>();
        final Module roboguiceModule = new RoboModule(contextScope, throwingContextProvider,
                contextProvider, resourceListener, viewListener, extrasListener, preferenceListener, this);
        modules.add(roboguiceModule);

        // Separate module required for testing eventmanager
        final Module eventManagerModule = new EventManagerModule(eventManager, contextProvider);
        modules.add(eventManagerModule);
        EventInspector eventInspector=new EventInspector(contextProvider, (EventBroker)eventManager,rootWorkItem);
        final Module cabModule = new CabModule(uiElementListener,eventInspector);
        modules.add(cabModule);
        
        //context observer manager module
        addApplicationModules(modules);
        for (Module m : modules)
            if (m instanceof AbstractAndroidModule)
                ((AbstractAndroidModule) m).setStaticTypeListeners(staticTypeListeners);
                    
        return Guice.createInjector(Stage.PRODUCTION, modules);
    }

    ////////////////////////////////////////////////////////////////////////////
    //--------------------------------- REVISIONS ------------------------------
    // Date       Name                 Tracking #         Description
    // ---------  -------------------  -------------      ----------------------
    // 13AUG2011  James Shen                 	          Code review
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Constructor
     * @param type type of the root work item.
     */
    public CabApplication(Class<TWorkItem> type) {
        workItemType=type;
    }
    
    @Override
    public void onCreate(){
        Injector injector=getInjector();
        rootWorkItem=injector.getInstance(workItemType);
    }

    ////////////////////////////////////////////////////////////////////////////
    //--------------------------------- REVISIONS ------------------------------
    // Date       Name                 Tracking #         Description
    // ---------  -------------------  -------------      ----------------------
    // 13AUG2011  James Shen                 	          Code review
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Starts the application.
     */
    public void run() {
        addRequiredServices();
        addServices();
        rootWorkItem.Run();
        start();
    }

    ////////////////////////////////////////////////////////////////////////////
    //--------------------------------- REVISIONS ------------------------------
    // Date       Name                 Tracking #         Description
    // ---------  -------------------  -------------      ----------------------
    // 13AUG2011  James Shen                 	          Code review
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Get the root work item.
     * @return the root work item.
     */
    public TWorkItem getRootWorkItem() {
        return rootWorkItem;
    }

    protected UIElementListener uiElementListener;
     
    protected TWorkItem rootWorkItem;
    
    private Class<TWorkItem> workItemType;
    
    ////////////////////////////////////////////////////////////////////////////
    //--------------------------------- REVISIONS ------------------------------
    // Date       Name                 Tracking #         Description
    // ---------  -------------------  -------------      ----------------------
    // 13AUG2011  James Shen                 	          Code review
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Add services.
     */
    protected void addServices() {
    }

    

    ////////////////////////////////////////////////////////////////////////////
    //--------------------------------- REVISIONS ------------------------------
    // Date       Name                 Tracking #         Description
    // ---------  -------------------  -------------      ----------------------
    // 13AUG2011  James Shen                 	          Code review
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Must be overriden. This method is called when the application is fully 
     * created and ready to run
     */
    protected abstract void start();
    
    ////////////////////////////////////////////////////////////////////////////
    //--------------------------------- REVISIONS ------------------------------
    // Date       Name                 Tracking #         Description
    // ---------  -------------------  -------------      ----------------------
    // 13AUG2011  James Shen                 	          Code review
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Add system required services.
     */
    private void addRequiredServices() {
        rootWorkItem.Services.addNew(SimpleWorkItemActivationService.class, 
                IWorkItemActivationService.class.getSimpleName());
    }

}
